home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / UTILITIE / CPU_MEMO / 0978.ZIP / FILES33.ASM < prev    next >
Assembly Source File  |  1987-07-03  |  16KB  |  329 lines

  1. ;****************************************************************************
  2. ; file: files33.asm    by: Steven M. Gibson, Irvine, CA        created: 06/06/87
  3. ;****************************************************************************
  4. ;
  5. ;          * * * PUBLIC DOMAIN COPYRIGHT RELEASE NOTICE * * *
  6. ;
  7. ; THIS PROGRAM, IN BOTH SOURCE CODE AND OBJECT FORM, HAS BEEN EXPLICITLY
  8. ; PLACED INTO THE PUBLIC DOMAIN BY ITS SOLE AUTHOR AND OWNER, STEVEN GIBSON,
  9. ; OF IRVINE, CA.  IT MAY THEREFORE BE FREELY REPRODUCED, EXCHANGED, UPLOADED
  10. ; AND DOWNLOADED.   HOWEVER THE AUTHOR REQUESTS THAT THIS NOTICE OF RELEASE
  11. ; AND ORIGIN OF AUTHORSHIP BE LEFT INTACT AND THAT THIS PROGRAM OR ITS DIRECT
  12. ; DERRIVATIVES, IF ANY, *NOT* BE SOLD FOR PROFIT.     ALSO, PLEASE KEEP THE
  13. ; ENTIRE SET OF FILES TOGETHER AS ONE PACKAGE.               ----> Thanks
  14. ;
  15. ;****************************************************************************
  16. ;
  17. ;  About The Program: FILES.COM              (source code file: files33.asm)
  18. ;
  19. ;  "FILES.COM" is a small resident (TSR) program which overcomes a major
  20. ;  glitch in the way IBM has implemented DOS 3.30.  Specifically, it handles
  21. ;  the requirements of explicitly ASKING DOS for additional handles and
  22. ;  keeping a block of RAM available for DOS when this request is made.
  23. ;  Any program can now have up to 256 files open when under 3.3 (counting
  24. ;  the standard pre-opened default files) if the command "FILES" is issued
  25. ;  first.  This program also has the interesting ability to spontaneously
  26. ;  remove itself ("Un-TSR") from memory after doing its job.
  27. ;
  28. ;  If you wish to suppress the message FILES delivers when it is run, simply
  29. ;  put anything after the command, (like: "files shhh") and it won't say a
  30. ;  word as it goes resident. Otherwise it makes a short (non-commercial)
  31. ;  statement of its intent as it terminates.
  32. ;
  33. ;  NOTE:  This program *ONLY* makes sense when under version 3.3 of DOS, and
  34. ;         it will refuse to run under any earlier DOS versions.  Use the
  35. ;      other DOS 3.x version of FILES.COM     (source file: files3x.asm)
  36. ;****************************************************************************
  37. ;
  38. ;             About These SOURCE CODE FILES:
  39. ;
  40. ;  This source code file, and the companion OPENER.ASM source code file, were
  41. ;  written to be instructional, clear, and a bit tutorial in nature. As such
  42. ;  they have been commented more heavily than normal self-communication
  43. ;  would normally dictate.  I hope you will find them interesting, useful,
  44. ;  and not overly verbose.  They are also examples of a general coding style
  45. ;  I've found to endure quite well.  Adopt it if you like it.
  46. ;
  47. ;  NOTE: These files were created using the incredible file editor: BRIEF
  48. ;
  49. ;****************************************************************************
  50. ;
  51. ;    To make a COM file from this ASM source code:
  52. ;
  53. ;    masm files33, files33;        <--- assemble the .asm to .obj
  54. ;    link files33;            <--- link the .obj to .exe
  55. ;    exe2bin files33 files33.com    <--- convert .exe to .com
  56. ;    del files33.obj            <--- delete the intermediate debris
  57. ;    del files33.exe
  58. ;
  59. ;****************************************************************************
  60.  
  61. ;----------------------------------------------------------------------------
  62. ;                 E Q U A T E S
  63. ;----------------------------------------------------------------------------
  64. CR            equ    0Dh        ; ASCII
  65. LF            equ    0Ah
  66. COM_TERMINATE        equ    20h        ; .COM program termination
  67.  
  68. DOS_FUNC        equ    21h        ; Interrupt to call DOS
  69.  DOS_PRINTSTRING    equ    09h        ; Dos Sub-Function Defs
  70.  DOS_SET_VECTOR        equ    25h
  71.  DOS_VERSION_NUMBER    equ    30h        ;    "    "
  72.  DOS_STAY_RESIDENT    equ    31h
  73.  DOS_GET_VECTOR        equ    35h
  74.  DOS_CREATE        equ    3Ch        ;    "    "
  75.  DOS_OPEN        equ    3DH
  76.  DOS_ALLOC        equ    48H
  77.  DOS_DEALLOC        equ    49H        ;    "    "
  78.  DOS_SETBLOCK        equ    4AH
  79.  SET_HANDLE_COUNT    equ    67h        ; <----- The *NEW* function!
  80.  
  81. NEW_HANDLE_COUNT    equ    256 + 1        ; so we cam have 256 files
  82. NEW_MAX_HANDLES        equ    256        ; assuming 256 handle params
  83. MINIMUM_VERSION        equ    3 * 256 + 30    ; version "3"."30"
  84.  
  85. ;----------------------------------------------------------------------------
  86. ;               C O D E    S E G M E N T
  87. ;----------------------------------------------------------------------------
  88. CODESEG    SEGMENT BYTE PUBLIC
  89.     ASSUME    CS:CODESEG, DS:CODESEG
  90.     ORG    02Ch            ; pointer to this program's environ
  91. Environment    LABEL WORD
  92.  
  93.     ORG    080h
  94. ParameterCount    LABEL BYTE        ; count of the command-line params
  95.  
  96.     ORG    100h            ; .com programs execute from 0100h
  97. ComStart:    jmp    TransientCode    ; jump over our resident portion
  98.  
  99. ;****************************************************************************
  100. ;               RESIDENT CODE PORTION BEGINS HERE
  101. ;****************************************************************************
  102.  
  103. OldDosInt    dd    ?        ; original int 21 vector pointer
  104. HoleSegment    dw    ?        ; segment location of the "hole"
  105.  
  106. ;----------------------------------------------------------------------------
  107.  
  108. ;----------------------------------------------------------------------------
  109. ; NOTE TO THE READER:  The following "resident portion" of the TSR will make
  110. ; *MUCH* more sense if you have FIRST read the "transient portion" below. I
  111. ; suggest that you jump ahead and read that first, then come back to here....
  112. ;----------------------------------------------------------------------------
  113.     
  114. Int21Intercept:
  115. ;----------------------------------------------------------------------------
  116. ;   The transient portion of this program pointed DOS' calling Interrupt 21
  117. ;   here before terminating itself.  Therefore we receive control every time
  118. ;   anyone does an Int21h call to DOS.  (Until we've fulfilled our mission)
  119. ;----------------------------------------------------------------------------
  120.         cmp    ah, DOS_OPEN        ; was the call an open handle?
  121.         je    MakeRoom        ; yep, see if we're alive
  122.         cmp    ah, DOS_CREATE        ; was it a create handle?
  123.         jne    Int21Continue        ; nope, so just pass it on
  124.  
  125. MakeRoom:    cmp    cs:HoleSegment, 0    ; did we already do our thing?
  126.         je    Int21Continue        ; yep, so don't do it again!
  127.  
  128.         push    ax            ; save the caller's calling
  129.         push    bx            ; parameters on "his" stack
  130.         push    es
  131.  
  132. ;----------------------------------------------------------------------------
  133. ;  Free up the memory block, located at "HoleSegment", which was previously
  134. ;  allocated by the transient portion of this program.
  135. ;----------------------------------------------------------------------------
  136.         mov    es, cs:HoleSegment    ; get the segment number
  137.         mov    cs:HoleSegment, 0    ; zero it so we don't again
  138.         mov    ah, DOS_DEALLOC
  139.         int    DOS_FUNC        ; and release that ram block 
  140.  
  141. ;----------------------------------------------------------------------------
  142. ;  Now use DOS 3.3's new function: "Set Handle Count" to get DOS to use the
  143. ;  RAM memory we've just now freed up for the purpose of allowing the handles
  144. ;----------------------------------------------------------------------------
  145.         mov    ah, SET_HANDLE_COUNT    ; ask DOS for mucho handles
  146.         mov    bx, NEW_HANDLE_COUNT    ; using the new 3.3 function
  147.         int    DOS_FUNC
  148.  
  149. ;----------------------------------------------------------------------------
  150. ;     Now we verrify that interrupt 21 is still pointing at us, and if so
  151. ;     we're able to re-point it to where it was originally pointing, (thus
  152. ;     un-vectoring ourselves) then release even ourselves from ram too!
  153. ;----------------------------------------------------------------------------
  154.         mov    ah, DOS_GET_VECTOR
  155.         mov    al, DOS_FUNC        ; get int 21's address
  156.         int    DOS_FUNC
  157.         cmp    bx, OFFSET Int21Intercept
  158.         jne    RestoreStack        ; it moved, so we must remain
  159.         mov    ax, es            ;
  160.         mov    bx, cs            ; can't compare segment regs,
  161.         cmp    ax, bx            ; <sigh> so we do it this way
  162.         jne    RestoreStack
  163.  
  164.  
  165. ;----------------------------------------------------------------------------
  166. ;  DOS' calling Interrupt 21 is still pointing at us, (as it should always be
  167. ;  unless some later resident program or the currently executing program has
  168. ;  changed it), so we're free to point it back to where it was pointing.
  169. ;----------------------------------------------------------------------------
  170.         push    dx            ; we need ds and dx so we
  171.         push    ds            ; stack them too for a moment
  172.         mov    dx, WORD PTR cs:OldDosInt
  173.         mov    ds, WORD PTR cs:OldDosInt+2
  174.         mov    ah, DOS_SET_VECTOR
  175.         mov    al, DOS_FUNC
  176.         int    DOS_FUNC
  177.         pop    ds            ; and restore caller's ds:dx
  178.         pop    dx
  179.  
  180. ;----------------------------------------------------------------------------
  181. ;  Now, since we're no longer in the Interrupt 21 calling chain, we're free
  182. ;  to leave ram too, so now we can release our own code segment as well!
  183. ;  Since the transient portion already freed our environment allocation, and
  184. ;  we just unhooked ourselves from Int21, this final release of our code seg
  185. ;  will create a contiguous free region underneath the currently running
  186. ;  application program which DOS will collect together and recover as soon
  187. ;  as the program running now terminates.  This means that we will have
  188. ;  completely and spontaneously removed ourselves from RAM.
  189. ;----------------------------------------------------------------------------
  190.         mov    ax, cs            ; get our own code segment        
  191.         mov    es, ax
  192.         mov    ah, DOS_DEALLOC
  193.         int    DOS_FUNC        ; and release our ram block 
  194.  
  195. ;----------------------------------------------------------------------------
  196. ;  Now we restore the caller's original parameters (remember, we got control
  197. ;  because he was doing a DOS call himself) and pass control on to DOS so 
  198. ;  that the caller's original job can be performed as if we were never here.
  199. ;----------------------------------------------------------------------------
  200. RestoreStack:    pop    es            ; now restore our working
  201.         pop    bx            ; registers
  202.         pop    ax
  203. Int21Continue:    jmp    cs:[OldDosInt]        ; and "jump" to DOS so that
  204.                         ; and caller's return is
  205.                         ; left at the top of the stack
  206.  
  207. ;****************************************************************************
  208. ;               END OF THE RESIDENT CODE
  209. ;****************************************************************************
  210.  
  211. ;----------------------------------------------------------------------------
  212.  
  213.  
  214. ;****************************************************************************
  215. ;        BEGINNING OF THE TRANSIENT (NON-RESIDENT) CODE
  216. ;****************************************************************************
  217.  
  218. ;----------------------------------------------------------------------------
  219. ;  This program makes NO sense under any versions of DOS prior to 3.3, so we
  220. ;  refuse to operate at all if we're using a prior DOS.
  221. ;----------------------------------------------------------------------------
  222. TransientCode:    mov    ah, DOS_VERSION_NUMBER    ; first we need to make sure
  223.         int    DOS_FUNC        ; this guy has DOS 3.3!
  224.         xchg    ah, al            ; make the number linear
  225.         cmp    ax, MINIMUM_VERSION
  226.         jae    MakeUsResident        ; yep, DOS ver 3.3 or later!
  227.  
  228.         mov    dx, OFFSET WrongDosMsg    ; nope, he's using a version
  229.         mov    ah, DOS_PRINTSTRING    ; of DOS prior to 3.3
  230.         int    DOS_FUNC
  231.         int    COM_TERMINATE        ; we're not "supposed" to quit
  232.                         ; this way anymore, but it's
  233.                         ; so easy!
  234. MakeUsResident:
  235. ;----------------------------------------------------------------------------
  236. ;  When DOS loads a program it is allocated ALL of the remaining contiguous
  237. ;  memory from its load-point to the end of ram, so we start by modifying
  238. ;  this allocation so that it just encompasses our own program's code...
  239. ;----------------------------------------------------------------------------
  240.         mov    bx, OFFSET EndOfTransient + 15 ; get our ending offset
  241.         mov    cl, 4            ; and compute the number of
  242.         shr    bx, cl            ; segments (the 15 rounds up)
  243.         mov    ah, DOS_SETBLOCK    ; now shrink our memory block
  244.         int    DOS_FUNC
  245.  
  246. ;----------------------------------------------------------------------------
  247. ;  Every program also receives a set of strings in its Environment Block.
  248. ;  Since we don't need this, it's polite to release it too.  (Actually it's
  249. ;  necessary if we, being a TSR, are ever to completely evacuate RAM.)
  250. ;  (Dos manages memory allocation on a segment-by-segment, paragraph-by-
  251. ;  paragraph basis.  So we always refer to allocated blocks of memory by
  252. ;  referencing that block's segment number.  In the case of our Environment
  253. ;  segment, our own PSP (program segment prefix) has a pointer to that seg.)
  254. ;----------------------------------------------------------------------------
  255.         mov    es, Environment        ; get our environment's seg
  256.         mov    ah, DOS_DEALLOC
  257.         int    DOS_FUNC        ; and release it too!
  258.  
  259. ;----------------------------------------------------------------------------
  260. ;  Now we grab up a block of memory large enough to allow DOS to open 256
  261. ;  files.  Our resident half will free this up when the time is right!
  262. ;----------------------------------------------------------------------------
  263.         mov    bx, (NEW_MAX_HANDLES+15)/16    ; use paragraphs
  264.         mov    ah, DOS_ALLOC
  265.         int    DOS_FUNC
  266.         mov    HoleSegment, ax        ; and save the block's segment
  267.                         ; for our resident half
  268.  
  269. ;----------------------------------------------------------------------------
  270. ;  Now, since our whole methodology involves having the resident portion
  271. ;  FREE UP this newly allocated ram block, then ask DOS for a lot of handles
  272. ;  WHEN the next-to-run program asks DOS to open or create a file for it, we
  273. ;  need to intercept all subsequent DOS calls until we're done with our job.
  274. ;  So we re-route Interrupt 21 through our resident half.
  275. ;----------------------------------------------------------------------------
  276.         mov    ah, DOS_GET_VECTOR        ; get the current
  277.         mov    al, DOS_FUNC            ; interrupt 21 value
  278.         int    DOS_FUNC
  279.         mov    WORD PTR OldDosInt  , bx    ; saving it in the
  280.         mov    WORD PTR OldDosInt+2, es    ; resident portion
  281.  
  282.         mov    dx, OFFSET Int21Intercept    ; that done, we set
  283.         mov    ah, DOS_SET_VECTOR        ; int 21 to point
  284.         mov    al, DOS_FUNC            ; to our resident
  285.         int    DOS_FUNC            ; module
  286.  
  287. ;----------------------------------------------------------------------------
  288. ;  Nearly done, and just to be quite clear, we say something appropriate to
  289. ;  our operator before we terminate ... but *ONLY* if he didn't specifically
  290. ;  ask as to remain silent.  The byte at location 80h in our PSP contains
  291. ;  the count of parameters on our invoking command line.  If this is not
  292. ;  zero, we're suppose to suppress all departing exclamation....
  293. ;----------------------------------------------------------------------------
  294.         cmp    ParameterCount, 0        ; is it zero?
  295.         jne    NowWeTSR            ; nope, so be quiet!
  296.  
  297.         mov    dx, OFFSET FilesMessage        ; yep, so we get to
  298.         mov    ah, DOS_PRINTSTRING        ; say goodbye now
  299.         int    DOS_FUNC
  300.  
  301. ;----------------------------------------------------------------------------
  302. ;  Finally we tell DOS that we're all through, asking it nicely to terminate
  303. ;  us but leave the first half of us resident.  That top half will be awakened
  304. ;  every time DOS is called until it's done its job.  "TransientCode" is the
  305. ;  beginning of our second half, and the "+15" does the right thing with
  306. ;  rounding as we convert into our paragraph size.
  307. ;----------------------------------------------------------------------------
  308. NowWeTSR:    mov    ah, DOS_STAY_RESIDENT        ; compute the number
  309.         mov    dx, OFFSET TransientCode + 15    ; of paragraphs to
  310.         mov    cl, 4                ; keep resident
  311.         shr    dx, cl
  312.         int    DOS_FUNC    ; this "call", being "TSR" never gets
  313.                     ; control returned by DOS
  314. ;----------------------------------------------------------------------------
  315. ;              T E X T    M E S S A G E S
  316. ;----------------------------------------------------------------------------
  317. WrongDosMsg    db    CR,LF, "This program only applies to DOS versions "
  318.         db    "3.3 and (presumably) later.  Sorry!",CR,LF,"$"
  319. FilesMessage    db    CR,LF
  320.         db    "The next program to run may open up to "
  321.         db    22h,"FILES=",22h," files."        ; asc(")=22h
  322.         db    CR,LF,"$"
  323. ;----------------------------------------------------------------------------
  324. EndOfTransient    = THIS BYTE        ;  the address of this label is used
  325.                     ;  to compute our load-module size
  326. CODESEG    ENDS
  327.     END    ComStart        ; and that's all there is to it!
  328.  
  329.